package crmdna.list;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.googlecode.objectify.ObjectifyFilter;

import crmdna.client.Client;
import crmdna.common.APIException;
import crmdna.common.APIResponse.Status;

public class ListCoreTest {
	private final LocalServiceTestHelper datastoreHelper = new LocalServiceTestHelper(
			new LocalDatastoreServiceTestConfig().setApplyAllHighRepJobPolicy());

	private final String client = "isha";

	@Before
	public void setUp() {
		datastoreHelper.setUp();
		ObjectifyFilter.complete();

		Client.create(client);
	}

	@After
	public void tearDown() {
		ObjectifyFilter.complete();
		datastoreHelper.tearDown();
	}

	@Test
	public void createTest() {
		try {
			ListCore.create(client, 1, null);
			assertTrue(false);
		} catch (APIException ex) {
			assertEquals(Status.ERROR_RESOURCE_INCORRECTLY_SPECIFIED,
					ex.statusCode);
		}

		try {
			ListCore.create(client, 1, "");
			assertTrue(false);
		} catch (APIException ex) {
			assertEquals(Status.ERROR_RESOURCE_INCORRECTLY_SPECIFIED,
					ex.statusCode);
		}

		ListProp listProp = ListCore.create(client, 1, "Test");
		assertEquals(1, listProp.listId);

		List<ListProp> listProps = ListCore.query(client, null);
		assertEquals(1, listProps.size());
		assertEquals(1, listProps.get(0).groupId);
		assertEquals("test", listProps.get(0).name);
		assertEquals("Test", listProps.get(0).displayName);
		assertEquals(0, listProps.get(0).numElements);

		// cannot create duplicate in the same group
		try {
			ListCore.create(client, 1, "TesT");
			assertTrue(false);
		} catch (APIException ex) {
			assertEquals(Status.ERROR_RESOURCE_ALREADY_EXISTS, ex.statusCode);
		}

		// can create list with existing name but in a different group
		listProp = ListCore.create(client, 2, "Test");
		// no exception
		assertEquals(2, listProp.listId);

		listProps = ListCore.query(client, null);
		assertEquals(2, listProps.size());
	}

	@Test
	public void addElementsTest() {
		ListProp listProp = ListCore.create(client, 1, "Test");
		assertEquals(1, listProp.listId);

		Set<Long> set1to20 = getElements(1, 20);
		listProp = ListCore.addElements(client, listProp.listId, set1to20);
		assertEquals(20, listProp.numElements);

		assertTrue(ListCore.getElements(client, listProp.listId).containsAll(
				set1to20));

		listProp = ListCore.addElements(client, listProp.listId,
				getElements(1, 100));
		assertEquals(100, listProp.numElements);

		listProp = ListCore.addElements(client, listProp.listId,
				getElements(101, 100));
		assertEquals(200, listProp.numElements);

		listProp = ListCore.addElements(client, listProp.listId,
				getElements(201, 800));
		assertEquals(1000, listProp.numElements);

		listProp = ListCore.addElements(client, listProp.listId,
				getElements(1001, 3000));
		assertEquals(4000, listProp.numElements);

		// duplicate should not be added
		listProp = ListCore.addElements(client, listProp.listId,
				getElements(1001, 6000));
		assertEquals(7000, listProp.numElements);
		Set<Long> set1to7000 = getElements(1, 7000);
		assertTrue(ListCore.getElements(client, listProp.listId).containsAll(
				set1to7000));

		listProp = ListCore.addElements(client, listProp.listId,
				getElements(1, 90000));
		assertEquals(90000, listProp.numElements);

		listProp = ListCore.addElements(client, listProp.listId,
				getElements(1, 270000));
		assertEquals(270000, listProp.numElements);

		listProp = ListCore.addElements(client, listProp.listId,
				getElements(1, 450000));
		assertEquals(450000, listProp.numElements);

		listProp = ListCore.addElements(client, listProp.listId,
				getElements(400001, 90000));
		assertEquals(490000, listProp.numElements);

		try {
			listProp = ListCore.addElements(client, listProp.listId,
					getElements(490001, 10001));			
			assertTrue(false);
		} catch (APIException ex) {
			assertEquals(Status.ERROR_RESOURCE_INCORRECTLY_SPECIFIED,
					ex.statusCode);
		}
	}

	Set<Long> getElements(long startValue, int numElements) {
		Set<Long> set = new HashSet<>();

		for (int i = 0; i < numElements; i++) {
			set.add(i + startValue);
		}

		return set;
	}
}
